﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Windows.Forms;
namespace lox_z12Class
{
    class AstPrinter : Expr.Visitor<string>, Stmt.Visitor<string>//java的是void ，还没想仔细。
    {
        public string print(Expr expr) { return expr.accept(this); }
        String print(Stmt stmt) { return stmt.accept(this); }
        public string visitBlockStmt(Stmt.Block stmt)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("(block ");

            foreach (Stmt statement in stmt.statements) {
                builder.Append(statement.accept(this));
            }

            builder.Append(")");
            return builder.ToString();
        }
        public String visitClassStmt(Stmt.Class stmt)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("(class " + stmt.name.lexeme);

            foreach (Stmt.Function method in stmt.methods) {
                builder.Append(" " + print(method));
            }

            builder.Append(")");
            return builder.ToString();
        }
        public string visitExpressionStmt(Stmt.Expression stmt) { return parenthesize(";", stmt.expression); }
        public String visitFunctionStmt(Stmt.Function stmt)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append("(fun " + stmt.name.lexeme + "(");

            foreach (Token param in stmt._params) {
                if (param != stmt._params[0])
                    builder.Append(" ");
                builder.Append(param.lexeme);
            }

            builder.Append(") ");

            foreach (Stmt body in stmt.body) {
                builder.Append(body.accept(this));
            }

            builder.Append(")");
            return builder.ToString();
        }
        public String visitIfStmt(Stmt.If stmt)
        {
            if (stmt.elseBranch == null) {
                return parenthesize2("if", stmt.condition, stmt.thenBranch);
            }

            return parenthesize2("if-else", stmt.condition, stmt.thenBranch, stmt.elseBranch);
        }
        public string visitPrintStmt(Stmt.Print stmt) { return parenthesize("print", stmt.expression); }
        public String visitReturnStmt(Stmt.Return stmt)
        {
            if (stmt.value == null)
                return "(return)";
            return parenthesize("return", stmt.value);
        }

        public string visitVarStmt(Stmt.Var stmt)
        {
            if (stmt.initializer == null) {
                return parenthesize2("var", stmt.name);
            }

            return parenthesize2("var", stmt.name, "=", stmt.initializer);
        }
        public String visitWhileStmt(Stmt.While stmt)
        {
            return parenthesize2("while", stmt.condition, stmt.body);
        }
        public String visitAssignExpr(Expr.Assign expr)
        {
            return parenthesize2("=", expr.name.lexeme, expr.value);
        }
        string Expr.Visitor<string>.visitBinaryExpr(Expr.Binary expr)
        {
            //parenthesize   置入括号内的意思。
            return parenthesize(expr._operator.lexeme, expr.left, expr.right);
        }
        public String visitCallExpr(Expr.Call expr) { return parenthesize2("call", expr.callee, expr.arguments); }
        public String visitGetExpr(Expr.Get expr) { return parenthesize2(".", expr._object, expr.name.lexeme); }
        string Expr.Visitor<string>.visitGroupingExpr(Expr.Grouping expr)
        {
            return parenthesize("group", expr.expression); 
        }

        string Expr.Visitor<string>.visitLiteralExpr(Expr.Literal expr)
        {
            if (expr.value == null)
                return "nil";

            return expr.value.ToString();
        }
        public String visitLogicalExpr(Expr.Logical expr)
        {
            return parenthesize(expr._operator.lexeme, expr.left, expr.right);
        }
        public String visitSetExpr(Expr.Set expr)
        {
            return parenthesize2("=", expr._object, expr.name.lexeme, expr.value);
        }

        public String visitThisExpr(Expr.This expr) { return "this"; }
        string Expr.Visitor<string>.visitUnaryExpr(Expr.Unary expr)
        {
            return parenthesize(expr._operator.lexeme, expr.right); 
        }

         public String visitVariableExpr(Expr.Variable expr) { return expr.name.lexeme; }
        private string parenthesize(String name,params Expr[] exprs)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("(").Append(name);
            foreach (Expr expr in exprs) {
                builder.Append(" ");
                builder.Append(expr.accept(this)); //【【这个地方就递归调用了。】】
            }
            builder.Append(")");

            return builder.ToString();
        }
        #region  没用到的  
        // Note: AstPrinting other types of syntax trees is not shown in the
        // book, but this is provided here as a reference for those reading
        // the full code.
        private string parenthesize2(string name, params Object[] parts)
        {
            StringBuilder builder = new StringBuilder();

            builder.Append("(").Append(name);
            transform(builder, parts);
            builder.Append(")");

            return builder.ToString();
        }

        private void transform(StringBuilder builder, Object[] parts)
        {
            foreach (Object part in parts) {
                builder.Append(" ");
                if (part is Expr) {
                    builder.Append(((Expr) part).accept(this));
                  } 
                  else if (part is Stmt) {
                    builder.Append(((Stmt) part).accept(this));
                }
                  else if (part is Token) {
                    builder.Append(((Token) part).lexeme);
                }
                else if (part is List<string>)//这个地方，Java是  List
                {
                    transform(builder, ((List<string>)part).ToArray());
                } else {
                    builder.Append(part);
                }
            }
        }
        #endregion

        //public static void main(String[] args)
        //{
        //    Expr expression = new Expr.Binary(
        //            new Expr.Binary(new Expr.Literal(123), new Token(TokenType.PLUS, "+", null, 1), new Expr.Literal(345)),
        //            new Token(TokenType.STAR, "*", null, 1),
        //            new Expr.Binary(new Expr.Literal(4), new Token(TokenType.PLUS, "-", null, 1), new Expr.Literal(3)));
        //    MessageBox.Show(new AstPrinter().print(expression));
        //}
    }
}
